﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AsmShaderConverter.HlslShader
{
    public class Swizzle
    {
        public static readonly char[] StandardXYZW = new char[] { 'x', 'y', 'z', 'w' };
        public static string GetSwizzle(HlslShader.HlslTypes type, int RegisterOffset, char[] inputSwizzle)
        {
            string newSwizzlese = string.Empty;

            for (int i = 0; i < inputSwizzle.Length; i++)
            {
                switch (type)
                {
                    case HlslTypes.halfFloat:
                    case HlslTypes.float1:
                    case HlslTypes.float2:
                    case HlslTypes.float3:
                    case HlslTypes.float4:
                        newSwizzlese += GetSwizzleFloat(inputSwizzle[i]);
                        break;
                    case HlslTypes.float3x2:
                    case HlslTypes.float3x3:
                    case HlslTypes.float4x2:
                    case HlslTypes.float4x3:
                    case HlslTypes.float4x4:
                    case HlslTypes.Matrix3x2:
                    case HlslTypes.Matrix3x3:
                    case HlslTypes.Matrix4x2:
                    case HlslTypes.Matrix4x3:
                    case HlslTypes.Matrix4x4:
                        newSwizzlese += GetSwizzleMatrix(inputSwizzle[i], RegisterOffset);
                        break;
                    default:
                        throw new NotImplementedException();

                }

            }

            return newSwizzlese;
        }

        private static string GetSwizzleMatrix(char swizzle, int RegisterOffset)
        {
            switch (swizzle)
            {
                case 'x': return "_m0" + RegisterOffset.ToString();
                case 'y': return "_m1" + RegisterOffset.ToString();
                case 'z': return "_m2" + RegisterOffset.ToString();
                case 'w': return "_m3" + RegisterOffset.ToString();
                default:
                    throw new Exception("Unknown Swizzle!");
            }
        }

        private static string GetSwizzleFloat(char swizzle)
        {
            string sourceSwizzle = "xyzw";
            if (sourceSwizzle.Length != 4)
                throw new Exception("Source Length should be 4");


            switch (swizzle)
            {
                case 'x': return sourceSwizzle.Substring(0, 1);
                case 'y': return sourceSwizzle.Substring(1, 1);
                case 'z': return sourceSwizzle.Substring(2, 1);
                case 'w': return sourceSwizzle.Substring(3, 1);
                default:
                    throw new Exception("Unknown Swizzle!");
            }
        }

        internal static void SetSwizzleLengthToDestination(AsmShader.Register destination, AsmShader.Register source)
        {
            if (source.swizzle.Length == 0)
                throw new Exception("swizzle length should not be zero.");

            if (destination.swizzle.Length < source.swizzle.Length)
            {
                string substring = new string(source.swizzle).Substring(0, destination.swizzle.Length);
                source.swizzle = substring.ToCharArray();
            }
        }

        internal static void SetSwizzleLengthTo3(AsmShader.Register register)
        {
            if (register.swizzle.Length < 3)
            {
                throw new Exception("too short swizzle length!");
            }

            string substring = new string(register.swizzle).Substring(0, 3);
            register.swizzle = substring.ToCharArray();
        }

        internal static char[] CorrectSwizzle(char[] source, char[] destination)
        {
            if (source.Length == 4)
                if (destination.Length < source.Length)
                {
                    char[] newSwizzle = new char[destination.Length];
                    for (int i = 0; i < destination.Length; i++)
                    {
                        switch (destination[i])
                        {
                            case 'x': newSwizzle[i] = source[0]; break;
                            case 'y': newSwizzle[i] = source[1]; break;
                            case 'z': newSwizzle[i] = source[2]; break;
                            case 'w': newSwizzle[i] = source[3]; break;
                        }
                    }
                    return newSwizzle;
                }

            return source;
        }
    }
}
